package genericity.sign;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.testng.annotations.Test;

/**
 * @author
 */
public class UsageOfSign {



}

class Home <T extends Collections> {
    private T collection;

    public Home(T collection) {
        this.collection = collection;
    }

    public T getCollection() {
        return collection;
    }
}

/**
 * 类层面上不能用 ? 通配符
 */
//class Zoo <? extends Collections> {
//
//}


class G1 <T extends Number> {
    private T price;

    /**
     * 当在类层次上使用了泛型，那么在声明变量时可以直接使用泛型字母
     */
    private Map<T, Integer> map;


//    private Map<S extends Enum<S>, Integer> map2;

    private Map<? extends Enum<?>, Integer> map3;



//    public Map<T, Integer> mergeMap(int key, int value) {
//        return this.map.merge(key, value, Integer::sum);
//    }

    /**
     * 当类中的成员变量有泛型参数时，处理这样的成员变量时参数要使用泛型表示，不能使用真实类型
     * 这个方法使用了泛型，但并不是个泛型方法
     * @param key
     * @param value
     * @return
     */
    public Map<T, Integer> mergeMap(T key, int value) {
        this.map.merge(key, value, Integer::sum);
        return map;
    }

    public T realPrice(T coe) {
        return price;
    }

    /**
     * 泛型类中的泛型方法
     */



}

class G2 {

    /**
     * 定义类时不使用泛型，声明变量时不能够直接使用泛型字母
     */
//    private T price2;

//     private <T extends Number> T price3;

    /**
     * 声明map能用泛型是因为Map是个泛型接口，跟类是不是泛型类无关
     */
    private Map<? extends Number, ? extends Number> map;


    /**
     * 泛型方法的基本介绍
     * @param clazz 传入的泛型实参
     * @return T 返回值为T类型
     * 说明：
     *     1）public 与 返回值中间<T>非常重要，可以理解为声明此方法为泛型方法。
     *     2）只有声明了<T> 的方法才是泛型方法，泛型类中的使用了泛型的成员方法并不是泛型方法。
     *     3）<T> 表明该方法将使用泛型类型T，此时才可以在方法中使用泛型类型T。
     *     4）与泛型类的定义一样，此处T可以随便写为任意标识，常见的如T、E、K、V等形式的参数常用于表示泛型。
     */
    public <T> T genericMethod(Class<T> clazz)throws InstantiationException ,
        IllegalAccessException{
        T instance = clazz.newInstance();
        return instance;
    }

    /**
     * 可变参数的泛型方法
     * @param args
     * @param <T>
     */
    public <T> void printMsg( T... args){
        for(T t : args){
            System.out.println("泛型测试, t is " + t);
        }
    }

}

class GenerateTest<T> {

    public void show_1(T t){
        System.out.println(t.toString());
    }

    /**
     * 在泛型类中声明了一个泛型方法，使用泛型E，这种泛型E可以为任意类型。可以类型与T相同，也可以不同。
     * 由于泛型方法在声明的时候会声明泛型<E>，因此即使在泛型类中并未声明泛型，编译器也能够正确识别泛型方法中识别的泛型。
     * @param t
     * @param <E>
     */
    public <E> void show_3(E t){
        System.out.println(t.toString());
    }

    /**
     * 在泛型类中声明了一个泛型方法，使用泛型T，注意这个T是一种全新的类型，与泛型类中声明的T不是同一种类型
     *
     * @param t 泛型参数
     * @param <T> 表示返回值T是泛型，T只是一个占位符
     */
    public <T> void show_2(T t){
        System.out.println(t.toString());
    }

    /**
     * 这个方法中的T和泛型类中声明的T是同一种类型
     * @param t
     * @return
     */
    public T show3(T t) {
        System.out.println(t.toString());
        return t;
    }
}

/**
 * super用法
 */
class G3 <T extends Number> {

    private List<? super T> list;

}

class G4 <T> {

    private List<? super T> list;

    private List<? super Number> list2;

//    private List<T super Number> list3;

//    private T list3;


}

/**
 * super不能使用，
 * extends能使用，是因为一定能确认泛型的类型，
 * @param <T>
 */
class G5 <T> {

    public static void main(String[]args){


    }

}
